use crate::extern_lib::ThreadSafeShare;
use crate::flush_thread_pool;
use crate::submit;
use crate::utils;
use crate::utils::index_of;
use crate::utils::singleton::SingleInit;
use paste::paste;
use rusqlite::ffi::sqlite3;
use rusqlite::params;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::marker::PhantomData;
use std::ops::{Add, DerefMut, Index};
use std::sync::{Arc, Mutex};

lazy_static! {
    pub static ref TRAITS_MAP: std::sync::Arc<
        std::sync::Mutex<
            std::collections::HashMap<
                String,
                std::collections::HashMap<std::string::String, std::vec::Vec<(String, String)>>,
            >,
        >,
    > = std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));
}

// 获取元素类型
pub fn type_of_val<T: ?Sized>(_: &T) -> &str {
    std::any::type_name::<T>()
}
#[allow(non_snake_case)]
#[macro_export]
macro_rules! Fprintln {
    () =>{
      println!()
    };
    ($val:expr $(,)?) => {
        match &$val {
            tmp => {
                println!("{} = {:?}", stringify!($val), tmp);
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => {
        ($(Fprintln!($val)),+,)
    };

}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! DBG {
    () => {
        $crate::eprintln!("{}:{}", file!(), line!())
    };
    ($val:expr ) => {
        match &$val {
             tmp => {
                eprintln!("{}:{} {} = {:?} ( {} )",
                file!(), line!(), stringify!($val), tmp, utils::type_of_val(tmp));
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => {
        ($($self::DBG!($val)),+,)
    };
}

// 判断是否含有某一个trait
#[allow(non_snake_case)]
#[macro_export]
macro_rules! all_trait_build {
    ()=> {false};
    ($type:ty)=> {false};
    ($type:ty,$($trait_name:ty),*)=> {
            paste!{
            trait __InnerMarkerTrait {
                $(fn [<has_$trait_name>]()->bool{false})+
            }

            struct __TraitTest<T> {_maker: PhantomData<T>}
            $(
                        impl<T: $trait_name> __TraitTest<T> {
                            fn [<has_$trait_name>]()->bool{true}
                        }
            )+

            impl<T> __InnerMarkerTrait for __TraitTest<T> {}

        }
    };

}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! has_all_trait {
    ()=> {false};
    ($type:ty)=> {false};
    ($type:ty,$($trait_name:ty),*)=> {{
        let tmpVec = utils::macros_func::get_all_trait(stringify!($type));
        $(utils::macros_func::check_traits(&tmpVec.1,stringify!($trait_name))&&)*true
    }};
}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! has_any_trait {
    ()=> {false};
    ($type:ty)=> {false};
    ($type:ty,$($trait_name:ty),*)=> {{
        let tmpVec = utils::macros_func::get_all_trait(stringify!($type));
        $(utils::macros_func::check_traits(&tmpVec.1,stringify!($trait_name))||)*false
    }};
}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! has_none_trait {
    ()=> {false};
    ($type:ty)=> {false};
    ($type:ty,$($trait_name:ty),*)=> {{
        let tmpVec = utils::macros_func::get_all_trait(stringify!($type));
        !($(utils::macros_func::check_traits(&tmpVec.1,stringify!($trait_name))||)*false)
    }};
}

// 构建所有Trait表
#[allow(non_snake_case)]
#[macro_export]
macro_rules! build_has_trait_list {
    ($($trait_name:ty),+)=>{
    paste!{
           pub trait __InnerMarkerTrait {
                $(fn [<has_$trait_name>]()->bool{false})+
            }

           pub struct __TraitTest<T> {_maker: PhantomData<T>}
            $(
                        impl<T: $trait_name> __TraitTest<T> {
                            fn [<has_$trait_name>]()->bool{true}
                        }
            )+

            impl<T> __InnerMarkerTrait for __TraitTest<T> {}

        }
    };
}

pub fn get_all_trait(
    ty: &str,
) -> (
    String,
    std::collections::HashMap<String, std::vec::Vec<(String, String)>>,
) {
    // 已有缓存
    if let Some((k, v)) = utils::macros_func::TRAITS_MAP
        .lock()
        .unwrap()
        .get_key_value(ty)
    {
        return (k.clone(), v.clone());
    };

    #[derive(Debug)]
    struct TraitInfoTmp<'a> {
        scope: &'a str,
        infos: Vec<(String, String)>,
    }

    let mut arc = Vec::new();
    let sqlite_connection = rusqlite::Connection::open("src/repos/t_index.dat").unwrap();
    for scope in &["INNER_SCOPE", "OUTER_SCOPE"] {
        let mut statement = sqlite_connection
            .prepare(
                format!(
                    r#"
select SPECIFIC, CLASS_NAME||' - '||TRAIT as DESCP
from main.TRAIT_INDEX
where SCOPE = '{scope}' and CLASS_NAME like ' {ty}<%'
   or CLASS_NAME like ' {ty} %'
   or CLASS_NAME like ':{ty}<%'
   or CLASS_NAME like ':{ty} %'
order by CLASS_NAME
        "#
                )
                .as_str(),
            )
            .unwrap();
        let infos = statement
            .query_map([], |row| {
                Ok((
                    row.get::<usize, String>(0).unwrap(),
                    row.get::<usize, String>(1).unwrap(),
                ))
            })
            .unwrap()
            .into_iter()
            .map(|e| e.unwrap())
            .collect::<Vec<(String, String)>>();
        arc.push(TraitInfoTmp { scope, infos });
    }

    // let mut map = std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashMap::new()));
    //
    // for file_path in crate::extern_lib::find_file_all("src/repos", "traits_index").unwrap() {
    //     map.lock()
    //         .unwrap()
    //         .insert(file_path.clone(), std::collections::HashSet::new());
    //     let map_clone = map.clone();
    //     let ty_clone = ty.to_string();
    //     submit!({
    //         for x in
    //             std::io::BufReader::new(std::fs::File::open(file_path.clone()).unwrap()).lines()
    //         {
    //             let tmp = x.unwrap();
    //             let s = tmp.as_str();
    //             let fcoma = utils::index_of(s, ";", 0).unwrap();
    //
    //             if utils::index_of_any(
    //                 s,
    //                 &[
    //                     crate::str_join!(" ", ty_clone.as_str(), "<").as_str(),
    //                     crate::str_join!(" ", ty_clone.as_str(), " ").as_str(),
    //                     crate::str_join!(":", ty_clone.as_str(), "<").as_str(),
    //                     crate::str_join!(":", ty_clone.as_str(), " ").as_str(),
    //                 ],
    //                 fcoma + 1,
    //             ) {
    //                 map_clone
    //                     .lock()
    //                     .unwrap()
    //                     .get_mut(&file_path)
    //                     .unwrap()
    //                     .insert(
    //                         utils::str_utils::sub_str(s, 0, fcoma)
    //                             .unwrap_or("")
    //                             .to_string(),
    //                     );
    //             }
    //         }
    //     });
    // }
    // flush_thread_pool!();
    //
    // let x = Arc::try_unwrap(map)
    //     .unwrap()
    //     .into_inner()
    //     .unwrap()
    //     .into_iter()
    //     .map(|(k, v)| (k, v.into_iter().collect::<Vec<_>>()))
    //     .collect::<HashMap<String, Vec<_>>>();

    TRAITS_MAP.lock().unwrap().insert(
        ty.to_string(),
        arc.into_iter()
            .map(|e| (e.scope.to_string(), e.infos))
            .collect::<HashMap<_, _>>(),
    );
    if let Some((k, v)) = utils::macros_func::TRAITS_MAP
        .lock()
        .unwrap()
        .get_key_value(ty)
    {
        return (k.clone(), v.clone());
    };
    panic!("failed gotten!");
}

#[allow(non_snake_case)]
#[macro_export]
macro_rules! list_all_traits {
    () => {
        false
    };
    ($type:ty) => {
        println!(
            "{:#?}",
            utils::macros_func::get_all_trait(stringify!($type))
        );
    };
}

pub fn has_traits(ty: &str, checkTy: &str) -> bool {
    for (_, x) in utils::macros_func::get_all_trait(ty).1 {
        for (x1, _) in x {
            let tmp_str = x1.as_str();
            if !tmp_str.contains("!marker") && tmp_str.contains(checkTy) {
                return true;
            }
        }
    }
    false
}

pub fn check_traits(
    traits: &std::collections::HashMap<std::string::String, std::vec::Vec<(String, String)>>,
    checkTy: &str,
) -> bool {
    for (_, tmp) in traits {
        for (x1, _) in tmp {
            let tmp_str = x1.as_str();
            if !tmp_str.contains("!marker") && tmp_str.contains(checkTy) {
                return true;
            }
        }
    }
    false
}
